package containers

import (
	"context"
	"fmt"
	"server/internal/common/biz"
	"server/internal/common/constant"
	"server/internal/utils"

	"github.com/docker/docker/api/types/container"
	"github.com/docker/docker/api/types/filters"

	"server/internal/svc"
	"server/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type ContainersLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

// get containers list
func NewContainersLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ContainersLogic {
	return &ContainersLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *ContainersLogic) Containers(req *types.ContainersReq) (resp []types.ContainersResp, err error) {

	containers, err := l.svcCtx.DockerCli.ContainerList(l.ctx, container.ListOptions{
		All:     req.All,
		Filters: withArgs(req),
	})
	if err != nil {
		fmt.Println("ContainerList error:", err)
	}

	if containers == nil || len(containers) == 0 {
		l.Logger.Errorf("Container Not Found")
		return nil, biz.ContainerNotFoundError
	}

	resp = make([]types.ContainersResp, 0, len(containers))
	for _, c := range containers {
		l.Logger.Debug(utils.PrintLog("container", c))
		resp = append(resp, types.ContainersResp{
			ID:      c.ID[:12],
			Image:   c.Image,
			Command: c.Command,
			Created: utils.FormatTimestamp(c.Created),
			Status:  c.Status,
			Ports: func() []types.Port {
				ports := c.Ports
				p := make([]types.Port, 0, len(ports))
				for _, port := range ports {
					p = append(p, types.Port{
						IP:          port.IP,
						PrivatePort: port.PrivatePort,
						PublicPort:  port.PublicPort,
						Type:        port.Type,
					})
				}
				return p
			}(),
			Names: c.Names[0],
			State: c.State,
		})
	}

	return
}

func withArgs(req *types.ContainersReq) filters.Args {
	args := filters.NewArgs()
	// status
	for _, status := range req.Status {
		args.Add(constant.Status, status)
	}
	// container_id
	if req.ContainerId != "" {
		args.Add(constant.ContainerId, req.ContainerId)
	}
	// container_name
	if req.ContainerName != "" {
		args.Add(constant.ContainerName, req.ContainerName)
	}
	// network_name
	if req.NetworkName != "" {
		args.Add(constant.NetworkName, req.NetworkName)
	}
	// volume_name
	if req.VolumeName != "" {
		args.Add(constant.VolumeName, req.VolumeName)
	}
	// image_name
	if req.ImageName != "" {
		args.Add(constant.ImageName, req.ImageName)
	}
	// label
	if req.Label != nil {
		for _, v := range req.Label {
			args.Add(constant.Label, v)
		}
	}
	return args
}
